#include "SettingsManager.h"

SettingsManager::SettingsManager(string SettingsFile, string rootname, bool autosave) : m_doc(), m_fileName(SettingsFile), m_autoSave(autosave), m_doc_good(false), m_rootname(rootname)
{
    ifstream file;

    // open file
    file.open(m_fileName.c_str());

    // parse the file
    parseStream(file);

    // close file
    file.close();
}

void SettingsManager::parseStream(istream& in)
{
    string tempLine;
    string tempDoc;

    m_file_good = in.good();

    // read whole file to tempDoc
    while(in.good()) {
        getline(in, tempLine);
        tempDoc += tempLine;
    }

    // allocate memory data for RapidXML and fill it with document contents
    m_doc_str = new char[tempDoc.length()+1];
    memcpy(m_doc_str, tempDoc.c_str(), tempDoc.length()+1);

    // parse the document
    try {
        m_doc.parse<0>(m_doc_str);
    } catch(parse_error err){
        m_doc_good = false;
    }
}

bool SettingsManager::save(ostream& out)
{
    // use RapidXML's ability to create xml-structure to a stream
    out << m_doc;
	return true;
}


SettingsManager::SettingsManager(istream &in, string rootname) : m_doc(), m_doc_good(false), m_rootname(rootname), m_autoSave(false)
{
    // read the inputstream and parse the data
    parseStream(in);
}

vector<string> SettingsManager::pathToList(string path)
{
    stringstream ss;
    string temp;
    vector<string> ret;

    ss << path;

    // get substrings until it's empty
    while(ss.good()) {
        getline(ss, temp, SETTINGS_MANAGER_PATH_DELIMITER);
        ret.push_back(temp);
    }

    return ret;
}

xml_attribute<>* SettingsManager::getAttrib(vector<string> nodeNames)
{
    xml_attribute<>* attrib;
    vector<string>::iterator current;
    xml_node<>* it = getFirstNode();
    xml_node<>* tmp = NULL;

    for(current = nodeNames.begin(); current!=nodeNames.end()-1; current++) {
        // Check for existence of the node
        if ((tmp = it->first_node((*current).c_str()))==NULL) {
            // does not exist, allocate some space for the node and it's name
            char *node_name = m_doc.allocate_string((*current).c_str());
            tmp = m_doc.allocate_node(node_element, node_name);

            // append new node
            it->append_node(tmp);
        }
        // go deeper
        it = tmp;
    }

    // we got to the last element, this is an attribute
    attrib = it->first_attribute((*current).c_str());
    if(attrib == NULL) {
        // attrib does not exist, allocate some space for it and it's name
        char *attr_name = m_doc.allocate_string((*current).c_str());
        attrib = m_doc.allocate_attribute(attr_name);

        // append attrib
        it->append_attribute(attrib);
    }

    return attrib;
}

xml_node<>* SettingsManager::getFirstNode()
{
    xml_node<>* ret = m_doc.first_node();

    if(ret==NULL) {
        // the doc does not have a node, create default DEFAULT_ROOT_NODE node
        char *node_name = m_doc.allocate_string(m_rootname.c_str());
        ret = m_doc.allocate_node(node_element, node_name);

        // append it to the document
        m_doc.append_node(ret);
    }

    return ret;
}

string SettingsManager::setSetting(string name, string val)
{
    string ret;

    // find attribute
    xml_attribute<>* attr = getAttrib(pathToList(name));

    // allocate space for value
    char *value = m_doc.allocate_string(val.c_str());

    // backup old value
    ret = attr->value();

    // set new value
    attr->value(value);

    // return value
    return ret;
}

string SettingsManager::getSetting(string name)
{
    // find attribute
    xml_attribute<>* attr = getAttrib(pathToList(name));

    // return value
    return attr->value();
}

bool SettingsManager::save()
{
    ofstream file(m_fileName.c_str());

    // file could not be created
    if(!file.good())
        return false;

    // write into file
    file << m_doc << endl;

    // close file
    file.close();

    return file.good();
}

SettingsManager::~SettingsManager()
{
    if(m_autoSave)
        save();

    delete m_doc_str;
}